www.gusucode.com > VC++ Canny算子提取边缘算法示例-源码程序 > VC++ Canny算子提取边缘算法示例-源码程序/code/源代码/DIBPrcs.cpp

    /*************************************************************************
 * 文件DIBPrcs.cpp用来存放有关DIB的操作函数
 * 文件头存放在GlobalApi.h中
 *************************************************************************
 */

#include "GlobalApi.h"
#include "stdafx.h"
#include "cdib.h"



/*************************************************************************
 *
 * \函数名称:
 *   GetSystemPalette()
 *
 * \输入参数:
 *   无
 *
 * \返回值:
 *   HPALETTE				- 系统调色板句柄
 *
 * \说明:
 *   该函数获得当前正在使用的系统调色板的句柄
 *
 *************************************************************************
 */
HPALETTE GetSystemPalette() 
{ 
	// 设备上下文
	HDC hDC;                

	// 声明调色板句柄、指针等临时变量
	static HPALETTE hPal = NULL;   
	HANDLE hLogPal;         
	LPLOGPALETTE lpLogPal;  

	// 当前系统调色板的颜色数
	int nColors;            
 
    	// 获得当前系统设备上下文
	hDC = GetDC(NULL); 
	if (!hDC) 
		return NULL; 
 
	// 获得当前系统调色板的颜色数目
	nColors = ( 1 << (GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES)));
    
	// 给调色板分配内存
	hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nColors * 
		sizeof(PALETTEENTRY)); 
	if (!hLogPal) 
		return NULL; 
 
	// 得到调色板内存指针
	lpLogPal = (LPLOGPALETTE)GlobalLock(hLogPal); 
 
	// 设置调色板信息
	lpLogPal->palVersion = 0x300; 
	lpLogPal->palNumEntries = nColors; 
 
	// 将系统的调色板拷贝到当前的逻辑调色板中
	GetSystemPaletteEntries(hDC, 0, nColors, 
            (LPPALETTEENTRY)(lpLogPal->palPalEntry)); 
 
	// 创建Windows调色板
	hPal = CreatePalette(lpLogPal); 
 
	// 释放已分配内存并删除临时对象
	GlobalUnlock(hLogPal); 
	GlobalFree(hLogPal); 
	ReleaseDC(NULL, hDC); 
 
	// 返回
	return hPal; 
} 
 

/*************************************************************************
 *
 * \函数名称:
 *   CopyPalette
 *
 * \输入参数:
 *   HPALETTE	hPalSrc			- 需要拷贝的源调色板句柄
 *
 * \返回值:
 *   HPALETTE				- 如果操作成功,则返回拷贝的调色板句柄
 *
 * \说明:
 *   该函数将创建一个新的调色板,并从指定的调色板拷贝调色板内容
 *
 *************************************************************************
 */
HPALETTE CopyPalette(HPALETTE hPalSrc)
{
	// 调色板指针,临时变量
	PLOGPALETTE     plogPal;

	// 声明一个调色板句柄和一个临时句柄
	HPALETTE        hPalette;
	HANDLE		hTemp;

	// 调色板表项数
	int             iNumEntries=0;
    
	// 获取调色板中的表项数
	iNumEntries = GetPaletteEntries(hPalSrc, 0, iNumEntries, NULL);
	if (iNumEntries == 0) 
		return (HPALETTE) NULL;

	// 分配调色板内存,得到句柄
	hTemp = GlobalAlloc(GHND, sizeof(DWORD) + sizeof(PALETTEENTRY)*iNumEntries);
	if (! hTemp)
		return (HPALETTE) NULL;

	// 得到调色板的指针
	plogPal = (PLOGPALETTE)GlobalLock(hTemp);
	if (! plogPal) 
		return (HPALETTE) NULL;

	// 设置调色板的信息
	plogPal->palVersion = 0x300;
	plogPal->palNumEntries = (WORD) iNumEntries;
    
	// 获取逻辑调色板中指定范围的调色板表项
	GetPaletteEntries(hPalSrc, 0, iNumEntries, plogPal->palPalEntry);

	// 创建一个Windows调色板
	hPalette = CreatePalette(plogPal);

	// 释放以分配的内存
	GlobalUnlock( hTemp );
	GlobalFree  ( hTemp );

	return hPalette;
}
 



/*************************************************************************
 *
 * \函数名称:
 *   ReadDIB
 *
 * \输入参数:
 *   CFile*			pFile		- 需要打开的DIB文件
 *   LPBITMAPINFOHEADER*	pLpBMIH		- DIB信息头指针的指针
 *   LPBYTE*			pLpImage	- DIB位图数据块指针的指针
 *
 * \返回值:
 *   BOOL				- 如果操作成功,则返回TRUE
 *
 * \说明:
 *   该函数将指定文件中的DIB文件载入,其中信息头和调色板放在*pLpBMIH中
 *   图象数据存放到*pLpImage中。
 *
 *************************************************************************
 */
 BOOL ReadDIB(CFile* pFile, LPBITMAPINFOHEADER* pLpBMIH, LPBYTE* pLpImage)
 {
	 // 临时存放信息的变量
 	int nCount, nSize;
	BITMAPFILEHEADER bmfh;

	// 信息头指针
	//LPBITMAPINFOHEADER lpBMIH;

	// DIB图象数据指针
	//LPBYTE lpImage;

	// 进行读操作
	try 
	{
		// 读取文件头
		nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
		if(nCount != sizeof(BITMAPFILEHEADER)) {
			throw new CException;
		}

		// 如果文件类型部位"BM",则返回并进行相应错误处理
		if(bmfh.bfType != 0x4d42) {
			throw new CException;
		}

		// 计算信息头加上调色板的大小,并分配相应的内存
		nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
		*pLpBMIH = (LPBITMAPINFOHEADER) new char[nSize];

		// 读取信息头和调色板
		nCount = pFile->Read(*pLpBMIH, nSize); 

		// 计算图象数据大小并设置调色板指针
		if((*pLpBMIH)->biSize != sizeof(BITMAPINFOHEADER)) {
			TRACE("Not a valid Windows bitmap -- probably an OS/2 bitmap\n");
			throw new CException;
		}

		// 如果图象数据内存大小为0,则重新计算
		if((*pLpBMIH)->biSizeImage == 0) {
			DWORD dwBytes = ((DWORD) (*pLpBMIH)->biWidth * (*pLpBMIH)->biBitCount) / 32;
			if(((DWORD) (*pLpBMIH)->biWidth * (*pLpBMIH)->biBitCount) % 32) {
				dwBytes++;
			}
			dwBytes *= 4;
			(*pLpBMIH)->biSizeImage = dwBytes * (*pLpBMIH)->biHeight;	
		}
		
		// 分配图象数据内存,并从文件中读取图象数据
		*pLpImage = (LPBYTE) new char[(*pLpBMIH)->biSizeImage];
		nCount = pFile->Read((*pLpImage), (*pLpBMIH)->biSizeImage); 
	}

	// 错误处理
	catch(CException* pe) 
	{
		AfxMessageBox("Read error");
		pe->Delete();
		return FALSE;
	}

	// 将指针赋值

	// 返回
	return TRUE;


 }


 /*************************************************************************
 *
 * \函数名称:
 *   MakeDIBPalette()
 *
 * \输入参数:
 *   LPVOID		lpvColorTable	- 颜色表指针
 *   LPBITMAPINFOHEADER lpBMIH		- DIB信息头指针
 *
 * \返回值:
 *   HPALETTE				- 如果成功,则调色板句柄
 *
 * \说明:
 *   该函数将读取颜色表,并创建一个Windows调色板,并返回此调色板的句柄
 *
 ************************************************************************
 */
HPALETTE MakeDIBPalette(LPVOID lpvColorTable,  LPBITMAPINFOHEADER lpBMIH)
{
	// 调色板句柄
	HPALETTE hPalette = NULL;				

	// 颜色表颜色数
	int nColorTableEntries;
	
	// 设置DIB中的调色板指针
	// lpvColorTable = (LPBYTE) lpBMIH + sizeof(BITMAPINFOHEADER);

	// 计算调色板的表项数
	if(lpBMIH->biClrUsed == 0) {
		switch(lpBMIH->biBitCount) {
			case 1:
				nColorTableEntries = 2;
				break;
			case 4:
				nColorTableEntries = 16;
				break;
			case 8:
				nColorTableEntries = 256;
				break;
			case 16:
			case 24:
			case 32:
				nColorTableEntries = 0;
				break;
			default:
				break;
		}
	}

	// 否则调色板的表项数就是用到的颜色数目
	else {
		nColorTableEntries = lpBMIH->biClrUsed;
	}

	ASSERT((nColorTableEntries >= 0) && (nColorTableEntries <= 256)); 

	// 如果不存在调色板,则返回FALSE
	if(nColorTableEntries == 0) return FALSE;

	// 给逻辑调色板分配内存
	LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) +
		nColorTableEntries * sizeof(PALETTEENTRY)];

	// 设置逻辑调色板的信息
	pLogPal->palVersion = 0x300;
	pLogPal->palNumEntries = nColorTableEntries;

	// 拷贝DIB中的颜色表到逻辑调色板
	LPRGBQUAD pDibQuad = (LPRGBQUAD) lpvColorTable;
	for(int i = 0; i < nColorTableEntries; i++) {
		pLogPal->palPalEntry[i].peRed = pDibQuad->rgbRed;
		pLogPal->palPalEntry[i].peGreen = pDibQuad->rgbGreen;
		pLogPal->palPalEntry[i].peBlue = pDibQuad->rgbBlue;
		pLogPal->palPalEntry[i].peFlags = 0;
		pDibQuad++;
	}

	// 创建逻辑调色板
	hPalette = ::CreatePalette(pLogPal);

	// 删除临时变量
	delete pLogPal;

	// 返回调色板句柄
	return hPalette;
}	

 /*************************************************************************
 *
 * \函数名称:
 *   PaintDIB()
 *
 * \输入参数:
 *   CDC*	pDC			- 指向将要接收DIB图象的设备上下文指针 
 *   LPBITMAPINFOHEADER lpBMIH		- DIB信息头指针
 *   LPBYTE		lpImage;	- DIB位图数据块地址 
 *   CPoint	origin			- 显示DIB的逻辑坐标
 *   CSize	size			- 显示矩形的宽度和高度
 *   HPALETTE	hPalette		- 指向DIB的调色板句柄
 *
 * \返回值:
 *   BOOL				- 如果成功,则返回TRUE
 *
 * \说明:
 *   该函数将DIB图象进行显示
 *
 ************************************************************************
 */
BOOL PaintDIB(CDC* pDC, LPBITMAPINFOHEADER lpBMIH, LPBYTE lpImage, CPoint origin, CSize size, HPALETTE hPalette)
{
	if(lpBMIH == NULL) return FALSE;

	// 如果调色板不为空,则将调色板选入设备上下文
	if(hPalette != NULL) {
		::SelectPalette(pDC->GetSafeHdc(), hPalette, TRUE);
	}

	// 设置显示模式
	pDC->SetStretchBltMode(COLORONCOLOR);

	// 在设备的origin位置上画出大小为size的图象
	::StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y,size.cx,size.cy,
		0, 0, lpBMIH->biWidth, lpBMIH->biHeight,
		lpImage, (LPBITMAPINFO) lpBMIH, DIB_RGB_COLORS, SRCCOPY);

	// 返回
	return TRUE;
}


/*************************************************************************
 *
 * \函数名称:
 *   ConvertDDBToDIB()
 *
 * \输入参数:
 *   HBITMAP	hBitmap			- 指向源数据的BITMAP句柄
 *   CDib*	pDibDst			- 指向转换目标的CDib对象指针
 *
 * \返回值:
 *   BOOL				- 如果操作成功,则返回TRUE
 *
 * \说明:
 *   该函数将源BITMAP类pDibSrc中的数据拷贝到pDibDst中,并对相应的数据成员赋值
 *
 *************************************************************************
 */

BOOL ConvertDDBToDIB(HBITMAP hBitmap, CDib* pDibDest, HPALETTE hPal)
{
	// 声明一个BITMAP结构
	BITMAP bm;

	// 设备上下文
	HDC hDC;
	
	// 象素位数
	WORD biBitCount;
	
	// 调色板表项数
	int nColorTableEntries;

	// 如果hBitmap句柄无效,则返回
	if(!hBitmap){
		return FALSE;
	}

	// 填充图象数据到bm中,其中最后一个参数表示接收这个指定的对象的指针
	if(!GetObject(hBitmap,sizeof(BITMAP),(LPBYTE)&bm)){
		return FALSE;
	}

	// 计算象素位数
	biBitCount=bm.bmPlanes*bm.bmBitsPixel;
	if(biBitCount<=1)
		biBitCount=1;
	else if(biBitCount<=4)
		biBitCount=4;
	else if(biBitCount<=8)
		biBitCount=8;
	else 
		biBitCount=24;

	// 计算调色板的尺寸
	// 如果biClrUsed为零,则用到的颜色数为2的biBitCount次方
	switch(biBitCount) {
		case 1:
			nColorTableEntries = 2;
			break;
		case 4:
			nColorTableEntries = 16;
			break;
		case 8:
			nColorTableEntries = 256;
			break;
		case 16:
		case 24:
		case 32:
			nColorTableEntries = 0;
			break;
		default:
			ASSERT(FALSE);
	}	
	ASSERT((nColorTableEntries >= 0) && (nColorTableEntries <= 256)); 

	// 分配DIB信息头和调色板的内存
	LPBITMAPINFOHEADER lpBMIH = (LPBITMAPINFOHEADER) new char
		[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries];

	lpBMIH->biSize = sizeof(BITMAPINFOHEADER); 
	lpBMIH->biWidth = bm.bmWidth; 
	lpBMIH->biHeight = bm.bmHeight; 
	lpBMIH->biPlanes = 1; 
	lpBMIH->biBitCount = biBitCount; 
	lpBMIH->biCompression = BI_RGB; 
	lpBMIH->biSizeImage = 0; 
	lpBMIH->biXPelsPerMeter = 0; 
	lpBMIH->biYPelsPerMeter = 0; 
	lpBMIH->biClrUsed = nColorTableEntries;
	lpBMIH->biClrImportant = nColorTableEntries;	

	// 获得设备上下文句柄
	hDC=GetDC(NULL);

	  // select and realize our palette 
 
	// 如果没有指定调色板,则从系统中获得当前的系统调色板
	if(hPal==NULL){
		hPal = GetSystemPalette();
	}
	hPal = SelectPalette(hDC, hPal, FALSE); 
	RealizePalette(hDC); 
 

	// 调用GetDIBits填充信息头,并获得图象数据的尺寸。注意这里图象数据指针为NULL
	GetDIBits( hDC, hBitmap, 0, (UINT)lpBMIH->biHeight, NULL, (LPBITMAPINFO)lpBMIH, DIB_RGB_COLORS);

	// 如果没有正确的获得图象数据尺寸,则重新计算
	if( lpBMIH->biSizeImage == 0 ){
		lpBMIH->biSizeImage=(((bm.bmWidth*biBitCount) + 31) / 32 * 4)*bm.bmHeight;
	}

	// 分配存放图象数据的内存
	LPBYTE lpImage = (LPBYTE) new char[lpBMIH->biSizeImage];

	// 调用GetDIBits加载图象数据,注意这里给出了图象数据指针

	// 如果加载图象数据不成功,则释放已经分配的内存,并返回FALSE
	if( GetDIBits( hDC, hBitmap, 0, (UINT)lpBMIH->biHeight, (LPBYTE)lpImage,
		(LPBITMAPINFO)lpBMIH, DIB_RGB_COLORS) == 0 ){
		//clean up and return NULL
		delete []lpImage;
		delete []lpBMIH;

		SelectPalette( hDC, hPal, TRUE );
		RealizePalette( hDC );
		ReleaseDC( NULL, hDC );
		
		return FALSE;
	}

	// 将指针保存在CDib对象的数据成员中
	pDibDest->m_lpBMIH  = lpBMIH;
	pDibDest->m_lpImage = lpImage;
	pDibDest->m_nBmihAlloc = pDibDest->m_nImageAlloc = pDibDest->crtAlloc;


	// 删除临时变量
	SelectPalette(hDC, hPal, TRUE); 
	RealizePalette(hDC); 
	ReleaseDC(NULL, hDC); 
	return TRUE;
}


/*************************************************************************
 *
 * \函数名称:
 *   CopyDIB()
 *
 * \输入参数:
 *   CDib*	pDibSrc			- 指向源数据的CDib对象指针
 *   CDib*	pDibDst			- 指向拷贝目标的CDib对象指针
 *
 * \返回值:
 *   BOOL				- 如果操作成功,则返回TRUE
 *
 * \说明:
 *   该函数将源CDib类pDibSrc中的数据拷贝到pDibDst中,并对相应的数据成员赋值
 *
 *************************************************************************
 */
BOOL CopyDIB(CDib* pDibSrc, CDib* pDibDst)
{
	// 将目的CDib对象清空
	pDibDst->Empty();
	
	// 计算信息头加上调色板的大小,并分配相应的内存
	int nSizeHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pDibSrc->m_nColorTableEntries;

	pDibDst->m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSizeHdr];
	pDibDst->m_nBmihAlloc = pDibDst->m_nImageAlloc = pDibDst->crtAlloc;

	try{
		
		// 拷贝信息头和调色板
		memcpy(pDibDst->m_lpBMIH,pDibSrc->m_lpBMIH,nSizeHdr);
		
		
		// 如果结构的长度不对,则进行错误处理
		if(pDibDst->m_lpBMIH->biSize != sizeof(BITMAPINFOHEADER)) {
			TRACE("Not a valid Windows bitmap -- probably an OS/2 bitmap\n");
			throw new CException;
		}

		// 保存图象数据内存大小到CDib对象的数据成员中
		pDibDst->m_dwSizeImage = pDibDst->m_lpBMIH->biSizeImage;

		// 如果图象数据内存大小为0,则重新计算
		if(pDibDst->m_dwSizeImage == 0) {
			DWORD dwBytes = ((DWORD) pDibDst->m_lpBMIH->biWidth * pDibDst->m_lpBMIH->biBitCount) / 32;
			if(((DWORD) pDibDst->m_lpBMIH->biWidth * pDibDst->m_lpBMIH->biBitCount) % 32) {
				dwBytes++;
			}
			dwBytes *= 4;
			pDibDst->m_dwSizeImage = dwBytes * pDibDst->m_lpBMIH->biHeight; 
		}

		// 设置DIB中的调色板指针
		pDibDst->m_lpvColorTable = (LPBYTE) pDibDst->m_lpBMIH + sizeof(BITMAPINFOHEADER);

		// 计算调色板的表项数
		pDibDst->ComputePaletteSize(pDibDst->m_lpBMIH->biBitCount);

		// 如果DIB中存在调色板,则创建一个Windows调色板
		pDibDst->MakePalette();

		// 分配图象数据内存,并拷贝图象数据
		pDibDst->m_lpImage = (LPBYTE) new char[pDibDst->m_dwSizeImage];
		memcpy(pDibDst->m_lpImage, pDibSrc->m_lpImage,pDibDst->m_dwSizeImage);
	}

	catch(CException* pe) 
	{
		AfxMessageBox("Copy DIB error");
		pDibDst->Empty();
		pe->Delete();
		return FALSE;
	}
	
	return TRUE;
}


/*************************************************************************
 *
 * \函数名称:
 *   CopyScreenToDIB
 *
 * \输入参数:
 *   LPRECT	lpRect			- 需要拷贝的屏幕区域
 *   CDib*	pDibDest		- 指向目标CDib对象的指针
 *
 * \返回值:
 *   BOOL				- 如果操作成功,则返回TRUE
 *
 * \说明:
 *   该函数将指定矩形位置内的屏幕内容拷贝到DIB中源CDib类pDibSrc中的数据拷贝到pDibDst中
 *
 *************************************************************************
 */
BOOL CopyScreenToDIB(LPRECT lpRect, CDib* pDibDest)
{
	// 屏幕设备上下文和内存设备上下文句柄
	HDC         hScrDC, hMemDC;         

	// 声明BITMAP临时句柄和以前的BITMAP句柄
	HBITMAP     hBitmap, hOldBitmap;    

	// 调色板句柄
	HPALETTE    hPalette;       
    
	// 获取矩形区域的坐标
	int         nX, nY, nX2, nY2;

	// DIB图象的高度和宽度
	int         nWidth, nHeight; 

	// 屏幕分辨率
	int         xScrn, yScrn;    
 
        // 如果给定的矩形区域为空,则不进行进一步的处理
	if (IsRectEmpty(lpRect)) 
		return FALSE; 
 
    	// 得到一个屏幕设备上下文
	hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL); 

	// 创建与屏幕设备兼容的内存设备上下文
	hMemDC = CreateCompatibleDC(hScrDC); 
 
	// 得到矩形的区域坐标
	nX = lpRect->left; 
	nY = lpRect->top; 
	nX2 = lpRect->right; 
	nY2 = lpRect->bottom; 
 
	// 得到屏幕的分辨率,以便后面的判断处理
	xScrn = GetDeviceCaps(hScrDC, HORZRES); 
	yScrn = GetDeviceCaps(hScrDC, VERTRES); 
 
	// 判断矩形区域是否超出屏幕
 
	if (nX < 0) 
		nX = 0; 
	if (nY < 0) 
	        nY = 0; 
	if (nX2 > xScrn) 
	        nX2 = xScrn; 
	if (nY2 > yScrn) 
	        nY2 = yScrn; 
 
	// 计算DIB图象的高度和宽度
	nWidth = nX2 - nX; 
	nHeight = nY2 - nY; 
 
	// 创建一个与屏幕设备上下文兼容的DDB位图
	hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight); 
 
	// 将DDB位图选入内存设备上下文
	hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap); 
 
	// 将屏幕中指定区域的图象传输到内存设备上下文中
	BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY); 
 
	// 然后将以前的图象选入,并得到屏幕区域的DDB图象句柄
	hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap); 
 
	// 将临时的设备上下文删除
	DeleteDC(hScrDC); 
	DeleteDC(hMemDC); 
 
	// 得到当前系统调色板
	hPalette = GetSystemPalette(); 
 
	// 将DDB图象转换为DIB图象
	pDibDest->ConvertFromDDB(hBitmap,hPalette);
	
	// 删除临时对象
	DeleteObject(hPalette); 
	DeleteObject(hBitmap); 
	
	return TRUE;
}